package com.weimob.cloud.api.config.impl;

import cn.hutool.core.util.StrUtil;
import com.weimob.cloud.api.config.WeimobAccessTokenStorageConfig;
import com.weimob.cloud.api.exception.WeimobApiException;
import com.weimob.cloud.api.token.rsp.WeimobAccessTokenRsp;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.time.Duration;
import java.time.temporal.ChronoUnit;

/**
 * 微盟 Redisson 默认存储实现类
 */
@Slf4j
public class WeimobAccessTokenRedissonStorageConfigImpl implements WeimobAccessTokenStorageConfig {

    private static final String DEFAULT_REDIS_KEY = "weimob:access_token";
    private static final String ACCESS_TOKEN_LOCK_KEY = "weimob:access_token_lock";

    private final RedissonClient redissonclient;
    private final String redisKey;

    public WeimobAccessTokenRedissonStorageConfigImpl(@NonNull RedissonClient redissonclient, String redisKey) {
        this.redissonclient = redissonclient;
        if (StrUtil.isBlank(redisKey)) {
            this.redisKey = DEFAULT_REDIS_KEY;
        } else {
            this.redisKey = redisKey;
        }
    }

    @Override
    public String getAccessToken() {
        return redissonclient.<String>getBucket(redisKey).get();
    }

    @Override
    public void setAccessToken(WeimobAccessTokenRsp accessTokenRsp) {
        if (accessTokenRsp.getExpiresIn() < 5) {
            // token有效期太短，下次重新获取
            return;
        }

        boolean locked = false;
        RLock lock = redissonclient.getLock(ACCESS_TOKEN_LOCK_KEY);
        try {
            lock.lock();
            locked = true;

            Duration duration = Duration.of(accessTokenRsp.getExpiresIn() - 60, ChronoUnit.SECONDS);
            redissonclient.getBucket(redisKey).set(accessTokenRsp.getAccessToken(), duration);
        } catch (IllegalStateException e) {
            log.error("设置微盟云 access token 加锁失败", e);
            throw new WeimobApiException("设置微盟云 access token 加锁失败", e);
        } catch (Exception e) {
            log.error("设置微盟云 access token 方法执行失败", e);
            throw new WeimobApiException("设置微盟云 access token 方法执行失败", e);
        } finally {
            if (locked) {
                lock.unlock();
            }
        }
    }
}
